﻿using System;
using System.Collections.Concurrent;
using System.Linq;

namespace RapidDownloader.Model.Helpers
{
    public static class Extensions
    {
        #region Fields

        private static readonly string[] names = { "day", "hour", "minute", "second" };
        private static readonly string[] sizeSuffixes = { " bytes", " KB", " MB", " GB" };

        #endregion

        #region Public methods

        public static Func<T, TResult> Memoize<T, TResult>(this Func<T, TResult> func)
        {
            var cache = new ConcurrentDictionary<T, TResult>();
            return key => cache.GetOrAdd(key, func);
        }

        public static string FormatSize(this long fileSize, string suffix = "", bool showFixedPoint = true)
        {
            return FormatSize((double)fileSize, suffix, showFixedPoint);
        }

        public static string FormatSize(this double fileSize, string suffix = "", bool showFixedPoint = true)
        {
            var j = 0;
            while (fileSize >= 1024d && j < sizeSuffixes.Length)
            {
                fileSize /= 1024d;
                j++;
            }
            return string.Concat(showFixedPoint && j >= 2 ? fileSize.ToString("F") : ((int)fileSize).ToString(), sizeSuffixes[j], suffix);
        }

        public static string Describe(this TimeSpan duration)
        {
            int[] ints = {
                             duration.Days,
                             duration.Hours,
                             duration.Minutes,
                             duration.Seconds
                         };

            double[] doubles = {
                                   duration.TotalDays,
                                   duration.TotalHours,
                                   duration.TotalMinutes,
                                   duration.TotalSeconds
                               };

            var firstNonZero = ints.Select((value, index) => new { value, index }).FirstOrDefault(x => x.value != 0);
            if (firstNonZero == null)
                return "Done";

            var i = firstNonZero.index;
            var quantity = (int)Math.Round(doubles[i]);
            return ((i >= 3) ? string.Empty : "± ") + Tense(quantity, names[i]);
        }

        #endregion

        #region Private Methods

        private static string Tense(int quantity, string noun)
        {
            return quantity == 1 ? "1 " + noun : string.Format("{0} {1}s", quantity, noun);
        }

        #endregion
    }
}